package com.qingzhuge.common.concurrent;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.apache.commons.lang3.StringUtils;

import java.util.Objects;
import java.util.concurrent.*;

/**
 * @author : zero.xiao
 * @description : 自定义线程池
 * @modified By:
 */
public class Executors {

    private static ThreadFactory threadFactory(String threadName) {
        return StringUtils.isEmpty(threadName) ? java.util.concurrent.Executors.defaultThreadFactory() :
                new ThreadFactoryBuilder()
                        .setNameFormat(Objects.requireNonNull(threadName) + "-%d")
                        .setDaemon(true)
                        .build();
    }

    /**
     * @param threadName      线程名称
     * @param corePoolSize    在池中保存的核心线程数，即使它们是空闲的
     * @param maximumPoolSize 在池中允许的最大线程数。
     * @param keepAliveTime   当线程的数量大于核心时，这是多余空闲线程在终止之前等待新任务的最大时间。
     * @param unit            参数的时间单位。
     * @param workQueue       工作队列用于在执行任务之前使用它。此队列只保留 execute方法提交的Runnable任务。
     * @return
     */
    public static ExecutorService newThreadPoolExecutor(String threadName,
                                                        int corePoolSize, int maximumPoolSize, long keepAliveTime,
                                                        TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        //Common Thread Pool
        return new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory(threadName),new QingRejectedExecutionHandler(threadName));
    }

    /**
     * 创建一个定长线程池，可控制线程最大并发数，超出的线程会在队列中等待。
     * 默认设置queue大小 1024
     *
     * @param threadName 线程名称
     * @param corePoolSize   核心线程数大小
     * @return ExecutorService
     */
    public static ExecutorService newFixedThreadPool(String threadName, int corePoolSize) {
        return newFixedThreadPool(threadName, corePoolSize, 1024);
    }

    /**
     * 创建一个定长线程池，可控制线程最大并发数，超出的线程会在队列中等待。
     *
     * @param threadName 线程名称
     * @param corePoolSize   核心线程数大小
     * @param queueSize  queue大小
     * @return ExecutorService
     */
    public static ExecutorService newFixedThreadPool(String threadName, int corePoolSize, int queueSize) {
        //使用了一个无界LinkedBlockingQueue存放阻塞任务
        return newThreadPoolExecutor(threadName, corePoolSize, corePoolSize, 0L,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(queueSize));
    }

    /**
     * 创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程，
     * 那么就会回收部分空闲（60秒不执行任务）的线程，当任务数增加时，此线程池又可以智能的添加新线程来处理任务。
     * 此线程池不会对线程池大小做限制，线程池大小完全依赖于操作系统（或者说JVM）能够创建的最大线程大小。
     *
     * @param threadName      线程名称
     * @param maximumPoolSize 在池中允许的最大线程数。
     * @return ExecutorService
     */
    public static ExecutorService newCachedThreadPool(String threadName, int maximumPoolSize) {
        //无容量的阻塞队列 SynchronousQueue
        return newThreadPoolExecutor(threadName, 0, maximumPoolSize, 60L,
                TimeUnit.SECONDS, new SynchronousQueue<>());
    }

    /**
     * 创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程，
     * 那么就会回收部分空闲（60秒不执行任务）的线程，当任务数增加时，此线程池又可以智能的添加新线程来处理任务。
     * 此线程池不会对线程池大小做限制，线程池大小完全依赖于操作系统（或者说JVM）能够创建的最大线程大小。
     * maximumPoolSize 在池中允许的最大线程数默认1024。
     *
     * @param threadName 线程名称
     * @return ExecutorService
     */
    public static ExecutorService newCachedThreadPool(String threadName) {
        return newCachedThreadPool(threadName, 1024);
    }

    /**
     * 创建一个单线程化的线程池，它只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
     *
     * @param threadName 线程名称
     * @return ExecutorService
     */
    public static ExecutorService newSingleThreadExecutor(String threadName) {
        return newFixedThreadPool(threadName, 1, 1);
    }

    /**
     * 创建一个线程池，它可安排在给定延迟后运行命令或者定期地执行。
     *
     * @param threadName      线程名称
     * @param corePoolSize    在池中保存的核心线程数大小，即使它们是空闲的
     * @param maximumPoolSize 在池中允许的最大线程数。
     * @return ScheduledExecutorService
     */
    public static ScheduledExecutorService newScheduledThreadPool(String threadName, int corePoolSize, int maximumPoolSize) {
        ScheduledThreadPoolExecutor executorService = new ScheduledThreadPoolExecutor(corePoolSize, threadFactory(threadName));
        executorService.setMaximumPoolSize(maximumPoolSize);
        return executorService;
    }

    /**
     * 创建一个线程池，它可安排在给定延迟后运行命令或者定期地执行。
     *
     * @param threadName   线程名称
     * @param corePoolSize 在池中保存的核心线程数大小，即使它们是空闲的
     * @return ScheduledExecutorService
     */
    public static ScheduledExecutorService newScheduledThreadPool(String threadName, int corePoolSize) {
        return newScheduledThreadPool(threadName, corePoolSize, 1024);
    }

    /**
     * 创建一个单线程执行程序，它可安排在给定延迟后运行命令或者定期地执行。
     *
     * @param threadName      线程名称
     * @param maximumPoolSize 在池中允许的最大线程数。
     * @return ScheduledExecutorService
     */
    public static ScheduledExecutorService newSingleThreadScheduledExecutor(String threadName, int maximumPoolSize) {
        return newScheduledThreadPool(threadName, 1, maximumPoolSize);
    }

    /**
     * 创建一个单线程执行程序，它可安排在给定延迟后运行命令或者定期地执行。
     *
     * @param threadName 线程名称
     * @return ScheduledExecutorService
     */
    public static ScheduledExecutorService newSingleThreadScheduledExecutor(String threadName) {
        return newScheduledThreadPool(threadName, 1, 1024);
    }


}
